#include "Qt3DPicker.h"

#include "OsgUtil.h"
#include "geometricUtility.h"

#include <Geom2dAPI_InterCurveCurve.hxx>
#include <Geom2d_Curve.hxx>
#include <GCE2d_MakeSegment.hxx>

#include "Chamfer2DHandler.h"
#include "CmdManager.h"
#include "Scene.h"
#include "SendPointHandlerBase.h"
#include "SelectHandler3D.h"
#include "OSGNodeMask.h"
#include "Operation/OpAdd.h"
#include "Operation/OpReplace.h"
#include "LineStrip2D.h"
#include "QtOSGWidget.h"
#include "OcctShapeProp.h"

bool Chamfer2DHandler::s_trim = true;
bool Chamfer2DHandler::s_byAngle = false;
double Chamfer2DHandler::s_dis1 = 0.;
double Chamfer2DHandler::s_dis2 = 0.;
float Chamfer2DHandler::s_angle = 0.;

Chamfer2DHandler::Chamfer2DHandler()
{
}

Chamfer2DHandler::~Chamfer2DHandler()
{
}

void Chamfer2DHandler::input(const QVariant& data, const QString& rawInput, CommandSource cs)
{
	auto scene = getScene();
	auto sph = getSendPointHandler();
	auto selector = qobject_cast<SelectHandler3D*>(getSelectHandler());
	if (data.type() == QVariant::Bool)
	{
		bool esc = !data.toBool();
		if (esc)
		{
			if(m_line1)
				m_line1->setSelected(false);
			selector->clearSelection();
			clearInput();
			emit finished();
			return;
		}
	}

	if (status() == 0)
	{
		if (selector)
		{
			selector->clearSelection();
			selector->beginSelect(D2LineMask, 1);
			prompt(1, tr("选择对象或[距离(D)/角度(A)/修剪(T)/方式(E)]:"));
		}
		else
		{
			emit finished();
		}
		return;
	}


	if (status() == 1)
	{
		if (rawInput == "D" || rawInput == "d")
		{
			prompt(2, tr("指定第一个倒角距离:"));
		}
		else if (rawInput == "A" || rawInput == "a")
		{
			prompt(4, tr("指定第一条直线的倒角长度:"));
		}
		else if (rawInput == "T" || rawInput == "t")
		{
			prompt(7, tr("输入修剪模式选项[修剪(T)/不修剪(N)]:"));
		}
		else if (rawInput == "E" || rawInput == "e")
		{
			prompt(6, tr("输入修剪方法[距离(D)/角度(A)]:"));
		}
		else
		{
			if (selector->done())
			{
				std::set<std::shared_ptr<INode>> nodes = selector->selectionSet();
				if (nodes.empty())
				{
					emit finished();
					return;
				}
				std::shared_ptr<INode> node = *nodes.begin();
				m_line1 = std::dynamic_pointer_cast<LineStrip2D>(node);
				auto parent = m_line1->getParent();
				UCS* ucs = dynamic_cast<UCS*>(parent);
				if (ucs)
				{
					m_ucs = ucs;
					bool success = getChoosePt(m_choosePt1);
					if (!success)
						return;
				}
				else
				{
					remark(tr("请选择二维图形"));
					emit finished();
					return;
				}
				selector->clearSelection();
				m_line1->setSelected(true);
				selector->beginSelect(D2LineMask, 1);
				prompt(8, tr("指定第二条直线:"));
			}
		}
		return;
	}

	if (status() == 2)
	{
		if (data.type() == QVariant::Double)
		{
			s_dis1 = data.value<double>();
			prompt(3, tr("指定第二个倒角距离:"));
		}
		return;
	}
	if (status() == 3)
	{
		if (data.type() == QVariant::Double)
		{
			s_dis2 = data.value<double>();
			prompt(1, tr("选择对象或[距离(D)/角度(A)/修剪(T)/方式(E)]:"));
		}
		return;
	}

	if (status() == 4)
	{
		if (data.type() == QVariant::Double)
		{
			s_dis1 = data.value<double>();
			prompt(5, tr("指定第一条直线的倒角角度:"));
		}
		return;
	}
	if (status() == 5)
	{
		if (data.type() == QVariant::Double)
		{
			double angle = data.value<double>();
			s_angle = angle * M_PI / 180;
			while (s_angle < 0)
				s_angle += 2 * M_PI;
			prompt(1, tr("选择对象或[距离(D)/角度(A)/修剪(T)/方式(E)]:"));
		}
		return;
	}
	if (status() == 6)
	{
		if (rawInput == "D" || rawInput == "d")
		{
			s_byAngle = false;
			prompt(1, tr("选择对象或[距离(D)/角度(A)/修剪(T)/方式(E)]:"));
		}
		else  if (rawInput == "A" || rawInput == "a")
		{
			s_byAngle = true;
			prompt(1, tr("选择对象或[距离(D)/角度(A)/修剪(T)/方式(E)]:"));
		}
		return;
	}
	if (status() == 7)
	{
		if (rawInput == "T" || rawInput == "t")
		{
			s_trim = true;
			prompt(1, tr("选择对象或[距离(D)/角度(A)/修剪(T)/方式(E)]:"));
		}
		else  if (rawInput == "N" || rawInput == "n")
		{
			s_trim = false;
			prompt(1, tr("选择对象或[距离(D)/角度(A)/修剪(T)/方式(E)]:"));
		}
		return;
	}

	if (status() == 8)
	{
		if (selector->done())
		{
			m_line1->setSelected(false);
			auto selections = selector->selectionSet();
			if (selections.size() == 1)
			{
				auto selection = *selections.begin();
				m_line2 = std::dynamic_pointer_cast<LineStrip2D>(selection);
				auto parent = m_line2->getParent();
				UCS* ucs = dynamic_cast<UCS*>(parent);
				if (ucs && ucs == m_ucs)
				{
					auto l1 = m_line1->getCurve2d();
					auto l2 = m_line2->getCurve2d();
					osg::Vec3d choosePt2;
					bool success = getChoosePt(choosePt2);
					if (!success)
						return;
					gp_Pnt2d ucsPnt1(m_choosePt1.x(), m_choosePt1.y());
					gp_Pnt2d ucsPnt2(choosePt2.x(), choosePt2.y());
					SectionParam hitPointInfo1, hitPointInfo2;
					success = getSectionParam(l1, ucsPnt1, hitPointInfo1);
					success = getSectionParam(l2, ucsPnt2, hitPointInfo2);
					if (!(success && success))
					{
						remark(tr("请重新选择直线"));
						selector->clearSelection();
						emit finished();
						return;
					}
					const int section1 = hitPointInfo1.sectionNo;
					const int section2 = hitPointInfo2.sectionNo;
					auto points1 = m_line1->getPoints();
					const int pointsSize = points1.size();
					if (m_line1 == m_line2)
					{
						if (
							(abs(section1 - section2) > 1 && abs(section1 - section2) != pointsSize - 2)||
							(abs(section1 - section2) == pointsSize - 2 && points1[0] != points1[pointsSize - 1])
							)
						{
							remark(tr("多段线中的直线必须是连续的"));
							selector->clearSelection();
							emit finished();
							return;
						}
					}
					const auto& curve1 = l1[section1];
					const auto& curve2 = l2[section2];
					Geom2dAPI_InterCurveCurve inter;
					inter.Init(basisCurve(curve1), basisCurve(curve2));
					if (inter.NbPoints() > 0)
					{
						auto pt = inter.Point(1);
						//两条直线的交点
						const osg::Vec3d interPt = { double(pt.X()),double(pt.Y()),0 };
						std::vector<osg::Vec3d> chamferPoints;
						auto points2 = m_line2->getPoints();
						osg::Vec3d line1Dir = points1[section1 + 1] - points1[section1];
						osg::Vec3d line2Dir = points2[section2 + 1] - points2[section2];
						osg::Vec3d chooseVec1 = m_choosePt1 - interPt;
						osg::Vec3d chooseVec2 = choosePt2 - interPt;
						//计算切割线的第一点
						line1Dir.normalize();
						osg::Vec3d beginPt, endPt;
						if (line1Dir * chooseVec1 > 0)
						{
							points1[section1] = interPt + (line1Dir * s_dis1);
							beginPt = points1[section1];
							endPt = points1[section1 + 1];
							chamferPoints.push_back(points1[section1]);
							if (section1 > 0 && s_trim == true)
							{
								points1.erase(points1.begin(), points1.begin() + section1);
							}
						}
						else
						{
							points1[section1 + 1] = interPt - (line1Dir * s_dis1);
							beginPt = points1[section1];
							endPt = points1[section1 + 1];
							chamferPoints.push_back(points1[section1 + 1]);
							if (points1.size() > section1 + 2 && s_trim == true)
							{
								points1.erase(points1.begin() + section1 + 2, points1.end());
							}
						}
						if (!isValidChamferPoint(beginPt, endPt, line1Dir, selector))
						{
							remark(tr("距离太大"));
							selector->clearSelection();
							emit finished();
							return;
						}
					
						std::shared_ptr<LineStrip2D> chamferLine = std::make_shared<LineStrip2D>(ucs);
						chamferLine->setColor(getCurrentColor());
						//角度倒角
						if (s_byAngle)
						{
							auto choosePtVec = interPt - chamferPoints[0];
							double cosAngle = cos(s_angle);
							double sinAngle = sin(s_angle);
							const double dx = choosePtVec.x();
							const double dy = choosePtVec.y();
							osg::Vec3d chamferVec1(
								dx * cosAngle - dy * sinAngle,
								dx * sinAngle + dy * cosAngle,
								0);
							osg::Vec3d point1, interPt1;
							point1 = chamferPoints[0] + chamferVec1;
							auto choosePtDir = (interPt - chamferPoints[0]) ^ (choosePt2 - chamferPoints[0]);
							auto chamferPtDir = (interPt - chamferPoints[0]) ^ (point1 - chamferPoints[0]);
							if (choosePtDir.z() * chamferPtDir.z() > 0)
							{
								//第一种情况
								chamferPoints.push_back(point1);
							}
							else
							{
								//第二种情况
								cosAngle = cos(-s_angle);
								sinAngle = sin(-s_angle);
								osg::Vec3d chamferVec2 = { dx * cosAngle - dy * sinAngle,
													dx * sinAngle + dy * cosAngle,0 };
								osg::Vec3d point2;
								point2 = chamferPoints[0] + chamferVec2;
								chamferPoints.push_back(point2);
							}
							CDblPoint chamferPt;
							bool success = XLineLine(
								CDblPoint(chamferPoints[0].x(),chamferPoints[0].y()), CDblPoint(chamferPoints[1].x(),chamferPoints[1].y()),
								CDblPoint(points2[section2].x(), points2[section2].y()), CDblPoint(points2[section2 + 1].x(), points2[section2 + 1].y()),
								chamferPt
							);
							if (!success)
							{
								remark(tr("倒角角度无效"));
								selector->clearSelection();
								emit finished();
								return;
							}
							chamferPoints[1] = osg::Vec3d( chamferPt.x,chamferPt.y,0 );
							chamferLine->setPoints(chamferPoints);
							//判断角度过大只有一边有倒角的情况
							if (chooseVec2 * (chamferPoints[1] - interPt) < 0)
							{
								remark(tr("倒角角度无效"));
								selector->clearSelection();
								emit finished();
								return;
							}
							//修剪第二条直线
							if (line2Dir * chooseVec2 > 0)
							{
								points2[section2] = chamferPoints[1];
								beginPt = points2[section2];
								endPt = points2[section2 + 1];
								if (section2 > 0 && s_trim == true)
								{
									points2.erase(points2.begin(), points2.begin() + section2);
								}
							}
							else
							{
								points2[section2 + 1] = chamferPoints[1];
								beginPt = points2[section2];
								endPt = points2[section2 + 1];
								if (points2.size() > section2 + 2 && s_trim == true)
								{
									points2.erase(points2.begin() + section2 + 2, points2.end());
								}
							}
							if (!isValidChamferPoint(beginPt, endPt, line2Dir, selector))
							{
								remark(tr("距离太大"));
								selector->clearSelection();
								emit finished();
								return;
							}
						}
						else
						{
							//计算切割线的第二点
							line2Dir.normalize();
							if (line2Dir * chooseVec2 > 0)
							{
								points2[section2] = interPt + (line2Dir * s_dis2);
								beginPt = points2[section2];
								endPt = points2[section2 + 1];
								chamferPoints.push_back(points2[section2]);
								if (section2 > 0 && s_trim == true)
								{
									points2.erase(points2.begin(), points2.begin() + section2);
								}
							}
							else
							{
								points2[section2 + 1] = interPt - (line2Dir * s_dis2);
								beginPt = points2[section2];
								endPt = points2[section2 + 1];
								chamferPoints.push_back(points2[section2 + 1]);
								if (points2.size() > section2 + 2 && s_trim == true)
								{
									points2.erase(points2.begin() + section2 + 2, points2.end());
								}
							}
							if (!isValidChamferPoint(beginPt, endPt, line2Dir, selector))
							{
								remark(tr("距离太大"));
								selector->clearSelection();
								emit finished();
								return;
							}
							chamferLine->setPoints(chamferPoints);
						}						
						// 记录下本次操作				
						auto undoStack = scene->undoStack();
						if (s_trim)
						{
							std::vector<std::shared_ptr<Ent>> origins;
							std::vector<std::shared_ptr<Ent>> replaces;
							origins.push_back(m_line1);
							auto cloneEnt1 = m_line1->clone();
							auto clone1 = std::dynamic_pointer_cast<LineStrip2D>(cloneEnt1);
							if (m_line1 == m_line2 )
							{
								auto chamferPoint = chamferPoints[1];
								if (section1 > section2)
								{
									points1.swap(points2);
									chamferPoint = chamferPoints[0];
								}
								if (abs(section2 - section1) == pointsSize - 2)
								{
									points1[points1.size() - 1] = chamferPoint;
									points1.push_back(points1[0]);
								}
								else
								{
									points1.insert(points1.end(), points2.begin(), points2.end());
								}
							}
							else if (points1.size() > 2 || points2.size() > 2)
							{
								if (points1[0] == chamferPoints[0])
								{
									std::reverse(points1.begin(), points1.end());
								}
								if (points2[0] != chamferPoints[1])
								{
									std::reverse(points2.begin(), points2.end());
								}
								points1.insert(points1.end(), points2.begin(), points2.end());
								origins.push_back(m_line2);
							}
							else
							{
								auto widget3D = getWidget();
								widget3D->pauseRenderThread();
								m_ucs->addChild(chamferLine);
								widget3D->resumeRenderThread();
								origins.push_back(m_line2);
								auto cloneEnt2 = m_line2->clone();
								auto clone2 = std::dynamic_pointer_cast<LineStrip2D>(cloneEnt2);
								clone2->setPoints(points2);
								replaces.push_back(clone2);
								replaces.push_back(chamferLine);
								clone2->setColor(ucs->getUCSColor());
								chamferLine->setColor(ucs->getUCSColor());
							}
							clone1->setPoints(points1);
							replaces.push_back(clone1);
							clone1->setColor(ucs->getUCSColor());
							undoStack->push(new OpReplace(origins, replaces));
						}
						else
						{
							std::set<std::shared_ptr<INode>> children;
							children.insert(chamferLine);
							chamferLine->setColor(ucs->getUCSColor());
							undoStack->push(new OpAdd(children));
						}
						selector->clearSelection();
						emit finished();
					}
					else
					{
						remark(tr("直线平行"));
						emit finished();
					}
				}
				else
				{
					remark(tr("直线不在同一平面内"));
					emit finished();
				}	
			}
		}
		return;
	}

}

bool Chamfer2DHandler::getChoosePt(osg::Vec3d& pt)
{
	auto widget3D = getWidget();
	osg::Vec2d cursor = widget3D->getCursorPoint();
	osg::Camera* camera = widget3D->getCamera();
	if (!camera)
	{
		emit finished();
		return false;
	}
	osg::Matrix VPW, invVPW;
	bool success = getCameraViewProjectionWindowMatrix(camera, VPW, invVPW);
	if (!success)
	{
		emit finished();
		return false;
	}
	osg::Vec3d worldPt(cursor.x(), cursor.y(), 0);
	worldPt = worldPt * invVPW;
	osg::Vec3d ucsPt;
	getViewPointOnPlane(*m_ucs, worldPt, ucsPt);
	pt = ucsPt;
	return true;
}

//判断距离是否过大
bool Chamfer2DHandler::isValidChamferPoint(osg::Vec3d & begin, osg::Vec3d & end, osg::Vec3d & vec, SelectHandler3D* selector)
{
	if ((end - begin) * vec < 0)
	{
		return false;
	}
	return true;
}
